local skynet = require "skynet"
local filename = "slotmgr.lua"
local filelog = require "filelog"
local queue = require "skynet.queue"
local base = require "base"
local redisdao = require "redisdao"
local tabletool = require "tabletool"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

local SlotTool = require "slottool"
require "zrdice3enum"

------------
--枚举类
local dices_three_normal = {
    [3]  = {{1,1,1},}, ---1
    [4]  = {{1,1,2},{1,2,1},{2,1,1},}, ---3
    [5]  = {{1,1,3},{1,2,2},{1,3,1},{2,1,2},{2,2,1},{3,1,1},},  ---6
    [6]  = {{1,1,4},{1,2,3},{1,3,2},{1,4,1},{2,1,3},{2,2,2},{2,3,1},{3,1,2},{3,2,1},{4,1,1},}, ---10
    [7]  = {{1,1,5},{1,2,4},{1,3,3},{1,4,2},{1,5,1},{2,1,4},{2,2,3},{2,3,2},{2,4,1},{3,1,3},
            {3,2,2},{3,3,1},{4,1,2},{4,2,1},{5,1,1},}, ---15
    [8]  = {{1,1,6},{1,2,5},{1,3,4},{1,4,3},{1,5,2},{1,6,1},{2,1,5},{2,2,4},{2,3,3},{2,4,2},
            {2,5,1},{3,1,4},{3,2,3},{3,3,2},{3,4,1},{4,1,3},{4,2,2},{4,3,1},{5,1,2},{5,2,1},
            {6,1,1}},   ---21
    [9]  = {{1,2,6},{1,3,5},{1,4,4},{1,5,3},{1,6,2},{2,1,6},{2,2,5},{2,3,4},{2,4,3},{2,5,2},
            {2,6,1},{3,1,5},{3,2,4},{3,3,3},{3,4,2},{3,5,1},{4,1,4},{4,2,3},{4,3,2},{4,4,1},
            {5,1,3},{5,2,2},{5,3,1},{6,1,2},{6,2,1}}, ---25
    [10] = {{1,3,6},{1,4,5},{1,5,4},{1,6,3},{2,2,6},{2,3,5},{2,4,4},{2,5,3},{2,6,2},{3,1,6},
            {3,2,5},{3,3,4},{3,4,3},{3,5,2},{3,6,1},{4,1,5},{4,2,4},{4,3,3},{4,4,2},{4,5,1},
            {5,1,4},{5,2,3},{5,3,2},{5,4,1},{6,1,3},{6,2,2},{6,3,1}}, ---27
    [11] = {{1,4,6},{1,5,5},{1,6,4},{2,3,6},{2,4,5},{2,5,4},{2,6,3},{3,2,6},{3,3,5},{3,4,4},
            {3,5,3},{3,6,2},{4,1,6},{4,2,5},{4,3,4},{4,4,3},{4,5,2},{4,6,1},{5,1,5},{5,2,4},
            {5,3,3},{5,4,2},{5,5,1},{6,1,4},{6,2,3},{6,3,2},{6,4,1}}, ---27
    [12] = {{1,5,6},{1,6,5},{2,4,6},{2,5,5},{2,6,4},{3,3,6},{3,4,5},{3,5,4},{3,6,3},{4,2,6},
            {4,3,5},{4,4,4},{4,5,3},{4,6,2},{5,1,6},{5,2,5},{5,3,4},{5,4,3},{5,5,2},{5,6,1},
            {6,1,5},{6,2,4},{6,3,3},{6,4,2},{6,5,1}}, ---25
    [13] = {{1,6,6},{2,5,6},{2,6,5},{3,4,6},{3,5,5},{3,6,4},{4,3,6},{4,4,5},{4,5,4},{4,6,3},
            {5,2,6},{5,3,5},{5,4,4},{5,5,3},{5,6,2},{6,1,6},{6,2,5},{6,3,4},{6,4,3},{6,5,2},
            {6,6,1},},   ---21
    [14] = {{2,6,6},{3,5,6},{3,6,5},{4,4,6},{4,5,5},{4,6,4},{5,3,6},{5,4,5},{5,5,4},{5,6,3},
            {6,2,6},{6,3,5},{6,4,4},{6,5,3},{6,6,2}}, ---15
    [15] = {{3,6,6},{4,5,6},{4,6,5},{5,4,6},{5,5,5},{5,6,4},{6,3,6},{6,4,5},{6,5,4},{6,6,3},}, --- 10
    [16] = {{4,6,6},{5,5,6},{5,6,5},{6,4,6},{6,5,5},{6,6,4}}, ---6
    [17] = {{5,6,6},{6,5,6},{6,6,5}}, ---3
    [18] = {{6,6,6}}, ---1 
}

local dices_three_sum_weights = {
    [3] = 1,
    [4] = 3,
    [5] = 6,
    [6] = 10,
    [7] = 15,
    [8] = 21,
    [9] = 25,
    [10] = 27,
    [11] = 27,
    [12] = 25,
    [13] = 21,
    [14] = 15,
    [15] = 10,
    [16] = 6,
    [17] = 3,
    [18] = 1,
}

--系统输钱上限基值,默认10万
local SystemLoseLimit_Base = 1000000

--系统输钱上限控制系数
local SystemLoseLimit_Factor = 0.08

--开奖类型
local LotteryType = {
    LOTTERY_TYPE_SYSTEM_WIN = 1,   --系统必赢
    LOTTERY_TYPE_SYSTEM_LOSE = 2,  --系统必输
    LOTTERY_TYPE_NORMAL = 3,       --正常开奖
}
----------------------
--倍率列表
local Odds_list = {
    [1101] =  1 + 1,
    [1102] =  1 + 1,
    --------
    [2101] =  60 + 1,
    [2102] =  30 + 1,
    [2103] =  20 + 1,
    [2104] =  12 + 1,
    [2105] =   8 + 1,
    [2106] =   6 + 1,
    [2107] =   6 + 1,
    [2108] =   6 + 1,
    [2109] =   6 + 1,
    [2110] =   8 + 1,
    [2111] =  12 + 1,
    [2112] =  20 + 1,
    [2113] =  30 + 1,
    [2114] =  60 + 1,

    [2201] = 3 + 1,
    [2202] = 3 + 1,
    [2203] = 3 + 1,
    [2204] = 3 + 1,
    [2205] = 3 + 1,
    [2206] = 3 + 1,

    [2301] = 10 + 1,
    [2302] = 10 + 1,
    [2303] = 10 + 1,
    [2304] = 10 + 1,
    [2305] = 10 + 1,
    [2306] = 10 + 1,

    [2401] = 200 + 1,
    [2402] = 200 + 1,
    [2403] = 200 + 1,
    [2404] = 200 + 1,
    [2405] = 200 + 1,
    [2406] = 200 + 1,

    [2501] = 30 + 1,
}

local Weight_list = {
    [3] = 10,
    [4] = 30,
    [5] = 60,
    [6] = 100,
    [7] = 150,
    [8] = 210,
    [9] = 250,
    [10] = 270,
    [11] = 270,
    [12] = 250,
    [13] = 210,
    [14] = 150,
    [15] = 100,
    [16] = 60,
    [17] = 30,
    [18] = 10,
}

--系统库存概率表
--S = 库存值
local S_list = {
    [1] = { -- S < -500万
        nohit = 1.00,   --必不中概率
        normal = 0.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [2] = { -- -500万<=S<-100万
        nohit = 0.80,   --必不中概率
        normal = 0.20,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [3] = { -- -100万<=S<-20万
        nohit = 0.60,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [4] = { -- -20万<=S<-10万
        nohit = 0.30,   --必不中概率
        normal = 0.70,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [5] = { -- -10万<=S<200万
        nohit = 0.00,   --必不中概率
        normal = 1.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [6] = { -- 200万<=S<1000万
        nohit = 0.00,   --必不中概率
        normal = 0.80,  --正常开奖概率
        hit = 0.20,     --必中概率
    },
    [7] = { -- 1000万<=S<5000万
        nohit = 0.00,   --必不中概率
        normal = 0.60,  --正常开奖概率
        hit = 0.40,     --必中概率
    },
    [8] = { -- 5000万<=S<1亿
        nohit = 0.00,   --必不中概率
        normal = 0.50,  --正常开奖概率
        hit = 0.50,     --必中概率
    },
    [9] = { -- S>=1亿
        nohit = 0.00,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.60,     --必中概率
    },
}
--------------------------
--辅助表
--图标概率表，由权重表生成
local Prob_list = nil
--图标总权值,，由权重表生成
local Total_weight = nil
--预存牌型表,每种5种
local Profile_Cards_List = {           
}

local function check_want_type()
    local want_type = EDICEsType.DICE_TYPE_NORMAL
    local key = "dice3_want_open_type"
    local status, wanttype = redisdao.query_data(".gmmqredis", "get", key)
    if status and wanttype then
        want_type = tonumber(wanttype)
    end
    if want_type < EDICEsType.DICE_TYPE_NORMAL or want_type > EDICEsType.DICE_TYPE_QUANWEI then
        want_type = EDICEsType.DICE_TYPE_NORMAL
    end
    return want_type
end

local function get_sum_value()
    local sum_value = 0
    local key = "dice3_want_open_value"
    local status, want_value = redisdao.query_data(".gmmqredis", "get", key)
    if status and want_value then
        sum_value = tonumber(want_value)
    end
    if sum_value < 3 or sum_value > 18 then
        sum_value = 0
    end
    return sum_value
end

local function get_quanwei_value()
    local value = 0
    local key = "dice3_want_quanwei_value"
    local status, want_value = redisdao.query_data(".gmmqredis", "get", key)
    if status and want_value then
        value = tonumber(want_value)
    end
    if value < 1 and value > 6 then
        value = 0
    end
    return value
end



local function get_dicespoint(sum_id)
    local dices_pool = dices_three_normal[sum_id]
    if not dices_pool  then
        return {}
    else
        local want_type = check_want_type()
        if want_type == EDICEsType.DICE_TYPE_NORMAL then
            local get_index = base.get_random(1, #dices_pool)
            local get_dices = dices_pool[get_index]
            if not get_dices then
                return {}
            else
                return get_dices
            end
        elseif want_type == EDICEsType.DICE_TYPE_WEISHAI then
            local get_dices = {}
            local get_base = {1,2,3,4,5,6}
            local get_index = base.get_random(1,6)
            if get_index % 2 == 0 then
                local one_dice = table.remove(get_base, get_index)
                get_index = base.get_random(1, #get_base)
                for i = 1, 2 do
                    table.insert(get_dices, one_dice)
                end
                local two_dice = table.remove(get_base, get_index)
                table.insert(get_dices, two_dice)
            elseif get_index % 2 == 1 then
                local one_dice = table.remove(get_base, get_index)
                table.insert(get_dices, one_dice)
                get_index = base.get_random(1, #get_base)
                local two_dice = table.remove(get_base, get_index)
                for i = 1, 2 do
                    table.insert(get_dices, two_dice)
                end
            end
            for i = 1, #get_dices do
                if i > 1 then
                    local base_index = base.get_random(1, i)
                    get_dices[i], get_dices[base_index] = get_dices[base_index], get_dices[i]
                end
            end
            return get_dices
        elseif want_type == EDICEsType.DICE_TYPE_QUANWEI then
            local get_dices = {}
            local get = get_quanwei_value()
            if not get or get == 0 then
                get = base.get_random(1, 6)
            end
            for i = 1, 3 do
                table.insert(get_dices, get)
            end
            return get_dices
        else
            local get_index = base.get_random(1, #dices_pool)
            local get_dices = dices_pool[get_index]
            if not get_dices then
                return {}
            else
                return get_dices
            end
        end
    end
end

local function is_allsame(all_points)
    local is_all_same = false
    local same_value = 0
    if not all_points or #all_points ~= 3 then return is_all_same, same_value end
    is_all_same = true
    for index, point in pairs(all_points) do
        if same_value == 0 then same_value = point end
        if same_value ~= point then is_all_same = false break end
    end
    return is_all_same, same_value
end

local function is_twosame(all_points)
    local is_two_same = false
    local same_value = 0
    local not_same_value = 0
    if not all_points or #all_points ~= 3 then return is_two_same, same_value end
    for i = 1, 3 do
        for j = 1, 3 do
            if i ~= j then
                if all_points[i] == all_points[j] then
                    is_two_same = true
                    same_value = all_points[i]
                    break
                end
            end
        end
        if is_two_same == true and same_value ~= 0 then break end
    end
    if is_two_same == true and same_value ~= 0 then
        for index, point in ipairs(all_points) do
            if same_value ~= point then not_same_value = point break end
        end
    end
    ---filelog.sys_error("------is_twosame------", is_two_same, same_value, not_same_value)
    return is_two_same, same_value, not_same_value
end

--更新图标概率表
function SlotTool.update_picture_prob_list()
    local prob_list = {}

    local total_prob = 0
    local total_weight = SlotTool.calculate_total_weight(Weight_list)
    for id,w in pairs(Weight_list) do
        prob_list[id] = w / total_weight
        total_prob = total_prob + prob_list[id]
    end
        
    --总概率应为1
    if math.floor(total_prob * 100) ~= 100 then
        filelog.sys_error("total probability not equal to 1!",total_prob)
    end

    return prob_list,total_weight
end

--
--获取开奖类型
--返回 LotteryType类型
--
function SlotTool.get_lottery_type(gamename)
    --获取库存值
    local inventory = SlotTool.get_static_inventory_from_redis(gamename)

    local item = nil
    local s = inventory
    local a = 10000
    if s < -500 * a then
        item = S_list[1]
    elseif s >= -500 * a and s < -100 * a then
        item = S_list[2]
    elseif s >= -100 * a and s < -20 * a  then
        item = S_list[3]
    elseif s >= -20 * a and s < -10 * a then
        item = S_list[4]
    elseif s >= -10 * a and s < 200 * a then
        item = S_list[5]
    elseif s >= 200 * a and s < 1000 * a then
        item = S_list[6]
    elseif s >= 1000 * a and s < 5000 * a then
        item = S_list[7]
    elseif s >= 5000 * a and s < 10000 * a then
        item = S_list[8]
    elseif s >= 10000 * a then
        item = S_list[9]
    end

     --根据概率获取随机开奖类型
    local r = base.get_random(1, 1000)
    local hit = math.floor(item.hit * 1000)
    local nohit = hit + math.floor(item.nohit * 1000)
    local normal = nohit + math.floor(item.normal * 1000) 
    if r <= hit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_LOSE
    elseif r <= nohit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_WIN
    elseif r <= normal then
        return LotteryType.LOTTERY_TYPE_NORMAL
    end
end

--
--获取系统输赢列表
--
function SlotTool.get_system_win_lose_list(total_bet_list, total_bet, is_robot_banker)
    local sys_win_list = {}
    local sys_lose_list = {}

    if is_robot_banker then
        for id,odds in pairs(Odds_list) do
            local bet_id = id
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if rtm  < total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm > total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    else
        for id,odds in pairs(Odds_list) do
            local bet_id = id
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if rtm  > total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm < total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    end
    return sys_win_list,sys_lose_list
end

--比较玩家牌
--true 庄赢 false 闲赢
function SlotTool.compare_cards(banker_cards, player_cards)
    if not banker_cards or not player_cards then
        return
    end

    local banker_win = false
    local player_win = true
    if banker_cards.cards_type ~= player_cards.cards_type then   --比较牌型 至尊（2白板）> 对子（豹子） > 天杠（二八） > 单牌
        return (banker_cards.cards_type < player_cards.cards_type)
    elseif banker_cards.points ~= player_cards.points then       --牌型相同，比较点数
        if banker_cards.cards_type == SpecialPrize.SPECIAL_PRIZE_DUIZI then
            return (banker_cards.max_card < player_cards.max_card)
        else
            return (banker_cards.points < player_cards.points)
        end
    elseif banker_cards.max_card ~= player_cards.max_card then   --点数相同，比较单牌大小
        return (banker_cards.max_card < player_cards.max_card)
    elseif banker_cards.min_card ~= player_cards.min_card then   --点数相同，比较单牌大小
        return (banker_cards.min_card < player_cards.min_card)
    else
        return banker_win
    end
end

--
--获得系统输钱上限
--
function SlotTool.get_system_lose_limit(gamename)
    local loselimit = 0
    local S = SlotTool.get_static_inventory_from_redis(gamename)
    if S < 0 then
        loselimit = SystemLoseLimit_Base
    else
        loselimit = math.floor(S * SystemLoseLimit_Factor) + SystemLoseLimit_Base
    end

    return loselimit
end

--
--检测亏损值是否超过输钱上限
--
function SlotTool.check_is_greater_loselimit(id, total_bet, total_bet_list, is_robot_banker, loselimit)
    local rtm = SlotTool.get_rtm(id,total_bet_list)
    local ksz = total_bet - rtm
    if (is_robot_banker and ksz < -loselimit)
    or (not is_robot_banker and ksz > loselimit) then
        return true
    end

    return false
end

--
--获取系统必输随机结果
--去除超上限项
--
function SlotTool.get_mustlose_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)

    if sys_lose_list and #sys_lose_list > 0 then
        local lose_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_lose_list) do
            local is_ok = SlotTool.check_is_greater_loselimit(id,total_bet,total_bet_list,is_robot_banker,loselimit)
            if not is_ok then
                lose_w_list[id] = Weight_list[id]
                total_weight = total_weight + lose_w_list[id]
            end
        end
        
        if next(lose_w_list) ~= nil then
            return SlotTool.get_random_result_by_weightlist(lose_w_list,total_weight)
        else
            return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
        end
    end

    --当前押注使系统必定赢，则选择玩家赢钱最多的结果
    return SlotTool.get_max_spin_result(total_bet_list,is_robot_banker)
end

--
--获取系统必赢随机结果
--
function SlotTool.get_mustwin_random_result(sys_win_list, total_bet_list, is_robot_banker)
   if sys_win_list and #sys_win_list > 0 then
        local win_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_win_list) do
            win_w_list[id] = Weight_list[id]
            total_weight = total_weight + win_w_list[id]
        end
        
        local id = SlotTool.get_random_result_by_weightlist(win_w_list,total_weight)
        return id
    end

    --当前押注使系统必输，则选择玩家赢钱最少的结果
    return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
end

--
--获取普通随机结果
--去掉系统超上限亏损项
--
function SlotTool.get_normal_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local random_id_list = tabletool.deepcopy(Weight_list)

    --去除超上限亏损
    if sys_lose_list and #sys_lose_list > 0 then
        for _,id in pairs(sys_lose_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = 2
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)
            end
            local ksz =  total_bet - rtm
            if is_robot_banker and ksz < -loselimit then
                random_id_list[id] = nil
            elseif not is_robot_banker and ksz > loselimit then
                random_id_list[id] = nil
            end
        end
    end

    --所有项超上限，则返回最小的
    if next(random_id_list) == nil then
        return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
    end

    --产生随机结果
    return SlotTool.get_random_result_by_weightlist(random_id_list)
end

--
--获得纯随机结果
--
function SlotTool.get_real_random_result()
    local all_cards = {}
    local sum_id = get_sum_value()
    if sum_id == nil or sum_id == 0 then
        sum_id = SlotTool.get_random_result_by_weightlist(Weight_list)
    end
    local get_dices = get_dicespoint(sum_id)
    --filelog.sys_error("-----get_real_random_result-----", get_dices)
    --返回结果
    local result_list = {
        all_cards = {},
        prize_ids = {},
        all_sum = 0,
    }
    if #get_dices ~= 3 then
        return result_list
    end
    local alldicesum = 0
    for index, dice in ipairs(get_dices) do
        table.insert(result_list.all_cards, dice)
        alldicesum = alldicesum + dice
    end
    result_list.all_sum = alldicesum

    ----判断是否是围骰
    local is_all_same, same_value = is_allsame(result_list.all_cards)
    --filelog.sys_error("-------is_all_same, same_value----", is_all_same, same_value)
    if is_all_same == true and same_value ~= nil and same_value ~= 0 then
        table.insert(result_list.prize_ids, 2400 + same_value)
        table.insert(result_list.prize_ids, 2200 + same_value)
        table.insert(result_list.prize_ids, 2300 + same_value)
        table.insert(result_list.prize_ids, 2501)
    else
        if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
            table.insert(result_list.prize_ids, 1101)
        elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
            table.insert(result_list.prize_ids, 1102)
        end
        local is_two_same, two_same_value, one_value = is_twosame(result_list.all_cards)
        --filelog.sys_error("-----is_two_same, two_same_value, one_value-----", is_two_same, two_same_value, one_value)
        if is_two_same == true and two_same_value ~= nil and two_same_value ~= 0 then
            table.insert(result_list.prize_ids, 2300 + two_same_value)
            table.insert(result_list.prize_ids, 2200 + two_same_value)
            table.insert(result_list.prize_ids, 2200 + one_value)
        else
            --filelog.sys_error("-----no allsame and no twosame------")
            for index, value in ipairs(result_list.all_cards) do
                table.insert(result_list.prize_ids, 2200 + value)
            end
        end
    end
    local bit_id = EDICEBtnIDSum[alldicesum]
    table.insert(result_list.prize_ids, bit_id)
    result_list.all_sum = alldicesum
    --filelog.sys_error("------result_list------", result_list)
    return result_list
end

--
--获得可能的随机结果
--
function SlotTool.get_may_random_result(result_id)
    local all_cards = {}
    local real_all_cards = {}


    --返回结果
    local result_list = {
        all_cards = real_all_cards,
        prize_id = 0,
        ext_prize_list = prize_list,
        all_results = all_results,
    }

    return result_list
end

--
--产生一个随机旋转结果
--
function SlotTool.gen_random_dice_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local result_id = nil
    local result_list = nil
    --计算系统输赢列表
    local sys_win_list,sys_lose_list = SlotTool.get_system_win_lose_list(total_bet_list,total_bet,is_robot_banker)
    ---filelog.sys_error("----------sys_win_list,sys_lose_list-------", is_random, sys_win_list, sys_lose_list)
    --随机开奖
    if is_random then
        return SlotTool.get_real_random_result()
    else
        local lottery_type = SlotTool.get_lottery_type(gamename)
        --filelog.sys_error("-------lotterytype------", lottery_type)
        if lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_WIN then     --系统必赢
            result_id = SlotTool.get_mustwin_random_result(sys_win_list,total_bet_list,is_robot_banker)
        elseif lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_LOSE then  --系统必输
            result_id = SlotTool.get_mustlose_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        else    --随机开奖
            result_id = SlotTool.get_normal_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        end
    end

    --根据开牌结果获取随机牌
    --filelog.sys_error("--------------result_id-------------", result_id)
    local result_list = SlotTool.get_may_random_result(result_id)

    return result_list
end

--
--获取最小奖励
--
function SlotTool.get_min_spin_result(total_bet_list, is_robot_banker)
    local min_id = 0
    local min_rtm = 100000000000
    if not is_robot_banker then
        min_rtm = 0
    end
    
    --循环每一种情况,求返钱数最小的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds = 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if min_rtm > rtm then
                min_rtm = rtm
                min_id = id
            end
        else
            if min_rtm < rtm then
                min_rtm = rtm
                min_id = id
            end
        end
        
    end
    
    return min_id
end

--
--获取最大奖励
--
function SlotTool.get_max_spin_result(total_bet_list, is_robot_banker)
    local max_id = 0
    local max_rtm = 0
    if not is_robot_banker then
        max_rtm = 100000000000
    end
    
    --循环每一种情况,求返钱数最大的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds = 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if max_rtm < rtm then
                max_rtm = rtm
                max_id = id
            end
        else
            if max_rtm > rtm then
                max_rtm = rtm
                max_id = id
            end
        end
    end
    
    return max_id
end


--
--检测随机结果的正确性
--
function SlotTool.check_random_spin_result(spin_result)
    if not spin_result then
        return false
    end

    if #spin_result.all_cards ~= 3 then 
        return false
    end
    local is_ok = true

    for index, dice in pairs(spin_result.all_cards) do
        if dice < 1 or dice > 6 then
            is_ok = false
            break
        end
    end
    if is_ok == false then return is_ok end
    return is_ok
end

--
--处理送灯
--is_seq是否为连续灯
--
function SlotTool.handle_give_lamp(sd_w_list, is_seq)
    local result_list = {}

    --获得送灯数
    local lamp_num = SlotTool.get_random_result_by_weightlist(sd_w_list)
    if not lamp_num then
        return
    end

    --计算总权值
    local total_w = SlotTool.calculate_total_weight(SDFruit_weight_list)

    --随机获取lamp_num盏灯
    if is_seq then  --连续lamp_num盏灯
        local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
        table.insert(result_list,id)
        table.insert(result_list,lamp_num)
    else
        for i = 1,lamp_num do
            local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
            table.insert(result_list,id)
        end
    end
    
    return result_list
end

--
--处理闪电
--
function SlotTool.handle_lightning(lgtn_w_list)
    local result_list = {}

    --获得翻倍数
    local rate_num = SlotTool.get_random_result_by_weightlist(lgtn_w_list)
    if not rate_num then
        return
    end
    table.insert(result_list,rate_num)

    return result_list
end

--
--根据随机结果获取额外奖励项
--
function SlotTool.get_ext_prize_item(prize_id)
    
end

--
--保存奖励记录
--
function SlotTool.save_prize_records(gamename, opencard_result)
    local records = {}
    local key = (gamename or "") .. "_prize_records"
    local result,data = redisdao.query_data(".gmmqredis", "get", key)
    if result and data then
        records = json.decode(data) or {}
    end
    
    for _,prize_id in pairs(opencard_result) do
        local id = tostring(prize_id)
        records[id] = (tonumber(records[id]) or 0) + 1
    end
    records.total_count = (tonumber(records.total_count) or 0) + 1
    redisdao.query_data(".gmmqredis", "set", key, json.encode(records))

    ---------------------------------

    --辅助函数1
    local function helper_func(val)
        local cnt = 0
        local tmp = val
        while val >= 10 do
            val = math.floor(val / 10)
            cnt = cnt + 1
        end
        if math.floor(10^cnt) == tmp then
            return true
        end
        return false
    end

    --辅助函数2
    local function func(records)
        local porp_list = {}
        local subprop_list = {}
        local cnt = records.total_count or 0
        if cnt == 0 then
            return
        end

        for k,v in pairs(records) do
            if type(v) ~= "table" and k ~= "total_count" then
                v = tonumber(v) or 0
                porp_list[k] = string.format("%g%%",math.floor(v / cnt * 10000) / 100)
            elseif k == "total_count" then
                porp_list[k] = v
            else
                subprop_list[k] = func(v)
            end
        end
        return porp_list,subprop_list
    end

    --开奖次数每增加10倍，统计一次概率
    if helper_func(records.total_count) then
        local porp_list,subprop_list = func(records)
        filelog.sys_obj("prop_list", records.total_count, porp_list, "=================\n", subprop_list)
    end
    ---------------

    return true
end

--
--创建格式化赔率列表
--
function SlotTool.create_format_odds_list()
    local fmt_odds_list = {}

    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            if type(odds) == "table" then
                for i = 0,9 do
                    local real_odds = odds[i] or odds[1] or 2
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(real_odds)
                    table.insert(fmt_odds_list,val)
                end
            else
                for i = 0,9 do
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(odds)
                    table.insert(fmt_odds_list,val)
                end
            end
        end
    end
    
    return fmt_odds_list
end

--
--保存赔率列表到文件
--
function SlotTool.save_odds_list_to_file()
    local f = io.open("odds_list.lua","w+")
    if not f then
        filelog.print("open file error!")
        return
    end

    f:write("return { \n")
    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            if type(odds) == "table" then
                for i = 0,9 do
                    local real_odds = odds[i] or odds[1] or 2
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(real_odds)
                     f:write(tostring(val) .. ",")
                end
            else
                for i = 0,9 do
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(odds)
                     f:write(tostring(val) .. ",")
                end
            end
        end
    end
    f:write("}")
    f:close()
end

local function is_hit_prize(prize_ids, bet_item_id)
    local is_hit = false
    for index, prize_id in pairs(prize_ids) do
        if prize_id == bet_item_id then is_hit = true break end
    end
    return is_hit
end

-------------------------------
----------
--外部接口

local CMD = {}

local cs = queue()


function CMD.get_odds()
    return Odds_list
end

function CMD.get_odd_betid(result_list, bet_item_id)
    ---filelog.sys_error("-----CMD.get_odd_betid-----", result_list, bet_item_id)
    if not Odds_list[bet_item_id] then return end
    if bet_item_id >= 2201 and bet_item_id <= 2206 then
        local is_hit_award = is_hit_prize(result_list.prize_ids, bet_item_id)
        if is_hit_award == true then
            local is_all_same = is_allsame(result_list.all_cards)
            if is_all_same == true then
                return Odds_list[bet_item_id]
            else
                local is_two_same, two_same_value = is_twosame(result_list.all_cards)
                if is_two_same == true and bet_item_id % 100 == two_same_value then
                    return 3
                else
                    return 2
                end
            end
        else
            return 0
        end
    else
        return Odds_list[bet_item_id]
    end
end

function CMD.get_random_dice_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local cnt = 0
    while cnt < 3 do
        local isok,spin_result = skynet.pcall(SlotTool.gen_random_dice_result,gamename,total_bet_list,total_bet, avg_bet,is_robot_banker, is_random, banker_round)
        if isok and SlotTool.check_random_spin_result(spin_result) then
            return spin_result
        end
        cnt = cnt + 1
    end

    return false
end

--
--根据随机结果获取额外奖励
--
function CMD.get_ext_prize_result(prize_id)
    local ext_prize_result = {}

    --根据id获取奖励项
    local item = SlotTool.get_ext_prize_item(prize_id)
    if not item then
        return
    end

    --计算总权值
    local total_w = 0
    local w_list = {}
    for key,val in pairs(item) do
        if type(key) == "string" and string.sub(key,-1) == "w" then
            total_w = total_w + val
            w_list[key] = val
        end
    end
    
    --根据权值表，获取随机结果
    local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)
    if not key or key == "failed_w" then
        return
    end

    --获取额外奖励类型
    local len = string.len(key)
    local extprize_name = string.sub(key,1,len - 2)
    local extprize_type = Extra_prize_type[extprize_name]
    if not extprize_type then
        return
    end

    --获取奖励
    local extprize_list = nil
    
    --返回结果
    ext_prize_result.extprize_type = extprize_type
    ext_prize_result.extprize_list = extprize_list

    return ext_prize_result
end

--
--获取开局奖励
--
function CMD.get_start_prize_result(rids)
    local prize_result_list = {}

    if true then
        return {}
    end

    --获取随机结果
    local function get_random_result(prize_list)
        --计算总权值
        local total_w = 0
        local w_list = {}
        for key,val in pairs(prize_list) do
            if type(key) == "string" and string.sub(key,-1) == "w" then
                total_w = total_w + val
                w_list[key] = val
            end
        end
    
        --根据权值表，获取随机结果
        local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)

        return key
    end

    -------------------

     --开火车奖励表
    local drivetrain_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_KHC]

    --根据权值表，获取随机结果
    local key = get_random_result(drivetrain_list)
    if not key or key == "failed_w" then
        
    else
        local extprize_list = SlotTool.handle_give_lamp(drivetrain_list.sd_w_list,true)
        local item = {
            extprize_type = Extra_prize_type.drivetrain,
            extprize_list = extprize_list,
        }
        table.insert(prize_result_list,item)
    end

    ------------------

    rids = rids or {}
    
    --低于10人不触发
    local player_num = #rids
    if player_num < 10 then
        return prize_result_list
    end

     --判断是否触发鸿运当头
    local goodluck_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_HYDT]
    local key = get_random_result(goodluck_list)
    if not key or key == "failed_w" then
        return prize_result_list
    end

    --随机选取10%的人中奖
    local prize_coin_list = {}
    local total_w = SlotTool.calculate_total_weight(goodluck_list.coin_w_list)
    local hit_num = math.floor(player_num * 0.1)
    for i = 1,hit_num do
        local k = base.get_random(1,player_num)
        local rid = rids[k]
        local coin_num = SlotTool.get_random_result_by_weightlist(goodluck_list.coin_w_list,total_w)

        prize_coin_list[rid] = coin_num
        rids[k] = rids[player_num]
        table.remove(rids)
        player_num = #rids
    end
    
    if hit_num > 0 then
        local item = {
            extprize_type = Extra_prize_type.goodluck,
            extprize_list = prize_coin_list,
        }
        table.insert(prize_result_list,item)
    end
 
    return prize_result_list
end

--
--处理开奖
--
function CMD.handle_open_jackpot(gamename, jackpot_id, player_list)
    local award_list = {}

    --获取奖池金额
    local jackpot_money = SlotTool.get_jackpot_from_redis(gamename,jackpot_id)

    --随机开奖
    local total_coin = 0
    local max_level = 6
    for _,item in pairs(player_list) do
        local level = math.floor(item.game_num / 5)
        if level > max_level then
            level = max_level
        end
        local w_list = Jackpot_weight_list[level]
        local award_id = SlotTool.get_random_result_by_weightlist(w_list)
        local award_coin = math.floor(Jackpot_award_list[award_id] * jackpot_money * 0.01)
        local award_item = {
            rid = item.rid,
            logo = item.logo,
            rolename = item.rolename,
            award_money_num = award_coin,
        }
        table.insert(award_list, award_item)
        total_coin = total_coin + award_coin
    end
    
    return award_list,total_coin
end

--
--保存奖励记录
--
function CMD.save_prize_records(gamename, opencard_result)
  return cs(SlotTool.save_prize_records,gamename,opencard_result)
end

--
--处理庄家收益
--
function CMD.handle_banker_profit(ganmename, total_bet_num, player_win_num)
    local banker_win = total_bet_num - player_win_num
    return banker_win
end

--
--更新图标权值表
--
function CMD.update_picture_weight_list(new_w_list)
    if type(new_w_list) ~= "table" then
        return false
    end

    for k,v in pairs(new_w_list) do
        if Weight_list[k] and v >= 0 then
           Weight_list[k] = v
        end
    end
    
    --更新化概率表,总权值
    if next(new_w_list) ~= nil then
        Prob_list,Total_weight_list = SlotTool.update_picture_prob_list()
    end

    return true
end

--
--设置系统输钱上限
--
function CMD.set_system_lose_limit(loselimit_base, loselimit_factor)
    loselimit_base = loselimit_base or 0
    loselimit_factor = loselimit_factor or 0.02
    if loselimit_base < 0 or loselimit_factor < 0 then
        return false
    end
    SystemLoseLimit_Base = loselimit_base
    SystemLoseLimit_Factor = loselimit_factor

    return true
end

--
--获取格式化赔率列表
--
function CMD.get_format_odds_list()
    return SlotTool.create_format_odds_list()
end

--
--处理结算结果
--@total_change 总变化值
--@total_water  总流水值
--@total_bet    玩家总下注
--
function CMD.handle_balance_result(gamename, total_change, total_water, total_bet, comment)
    local tax_rate = SlotTool.get_tax_rate_from_redis(gamename)
    local profit_val = math.floor(total_bet * tax_rate * 100) / 100
    local inventory_val = -total_change

    --更新收益值
    local result1 = SlotTool.update_system_profit(gamename, profit_val, comment)
    if result1 then
        inventory_val = inventory_val - profit_val
    end

    --更新库存值，扣除抽水
    local service_fee_rate = SlotTool.get_service_fee_rate_from_redis(gamename)
    local service_fee_val = math.floor(total_water * service_fee_rate * 100) / 100
    inventory_val = inventory_val - service_fee_val

    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

--
--获取抽水率
--
function CMD.get_service_fee_rate(gamename)
    return SlotTool.get_service_fee_rate_from_redis(gamename)
end

-----------
--
--初始化
--
local function init()

    --初始化概率表,总权值
    Prob_list,Total_weight = SlotTool.update_picture_prob_list()
end

-------------------
--
skynet.start(function()
    init()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)